Thanks Ryan, I did some tests and got this working using the constructed plugin.
One issue I ran into though is that the inventory plugin files appear to be loaded alphabetically, so if the constructed inventory filename is alphabetically 'smaller', the constructed inventory file will be loaded first, and the host inventory may not yet be populated by the other inventory files. I found an issue logged about this:
https://github.com/ansible/ansible/issues/31405. I've got around this in the meantime by prefixing the name of my inventory file with 'z_'. It seems to me that Ansible's behaviour should be to always load constructed inventory files last since they rely purely on the output of other inventory plugins.
Anyway, just noting that extra bit of info here in case anyone stumbles upon this thread. Thanks again for your help!
Kind regards,
Guy