FLS is not sparse in Profiles. In other words, there is always a reference to every field in your Org to every one of your Profiles. Worst case scenario, every FLS is set to false for everything. That said, for what you are intending to do, there is definitely a way to do it. It is kind of a roundabout way though. Before I talk about that, here is one fact: Profiles are never created, just cloned. This is true whether you use the UI (where you choose the base Profile) or whether you use the API (where the system chooses "Standard User Profile" or "Standard Platform User Profile" depending on the license specified on the incoming Profile. In other words, if I try to create a new "Custom: System Administrator" profile using the API, the system will clone the "Standard User Profile" and then override the settings with the incoming settings. So, if you hand-code the Profile XML to not have any FLS, you still get FLS but they are from "Standard User Profile" and do not get overriden. But, lets say you do the right thing and send a complete FLS in your incoming XML. Great, FLS gets fixed up but now Object Permissions is still a problem (as it came from "Standard User Profile". Makes sense?
Now, here is how you fix this issue: Manually create a null-op Profile in the destination (create a Profile by cloning it off something and then turn everything off in it). Then manually create a new "Custom: System Administrator" Profile with this null-op as a base. Then, migrate your "Custom: System Administrator" XML from source to this destination. This will ensure that only the metadata that you send is set in this new Profile. Yes, this is, technically, not a new Profile anymore but the API matches by name and this method will work.
Once this is done, go to town with PermSets. PermSets' FLS is sparse so you can set only the ones that you want to set and leave everything else behind. This also works for revocations.
Happy to discuss more if you need more info.
Good luck,
Sridhar