I think it makes sense to have a standardized data structure which allows drivers to list the constraints for certain allocation types. When user space requests an allocation for use with certain devices, collect all these constraints in the ADF layer. This should be a mostly unprivileged operation.
The ADF layer would ask each allocator in turn if it could satisfy the superset of constraints for the current request. If no allocator can, fail verbosely. Then allow driver writers to implement a special allocator as a separate kernel object, which can satisfy a specific combination of constraints that appears on a particular platform (specific SoC with specific user-space). This should avoid growing all this craziness into user-space, while keeping the kernel interfaces as generic as possible under these circumstances.
Take all this with a grain of salt, though. I'm not yet as fluent in the android graphics stack as I'd like to be.