I haven't had the chance to see what is happening inside union-build yet, but did confirm that propagating expat/fixed instead of expat does not have the same problem.
I tried with (define fontconfig-fixed (package (inherit fontconfig) (propagated-inputs (modify-inputs (package-propagated-inputs fontconfig) (replace "expat" (@@ (gnu packages xml) expat/fixed)))))) and then (fhs-union (list fontconfig-fixed)) did not have any broken links trying to go to the wrong version. Using this also works around my original problem of a multi-arch union build having collisions (so that seems to stem from whatever is happening here).