OK so I'm going to shift this to an answer based on wesaw's responses.
There are two use cases. 1) When our mobile app queries for SF objects via Rest API - querying for permission set tables or for User.ProfileId fields results in 'Object/field does not exist' error or whatever
OK, so what you will need to do is a custom Apex REST service which queries the privileged information, filters it out based on business requirements, and divulges only the parts that are necessary for your mobile app to function properly. Ensure that no combination of parameters can result in divulging information a user should not be allowed to see. Assume your users are hackers and could call the REST service themselves.
2) When we are querying for the same right inside apex classes - by default Apex does not enforce object/field level security, but we are doing it on our own in our custom data access layer - that's where we are getting 'No permission error' to read object or field.
So ultimately, the purpose of your data access layer enforcing SOQL is to ensure that you do not divulge information that the end user is not entitled to. And certainly if a user does not have view setup permissions they will not have the object/field permissions for setup objects.
But there are plenty of valid use cases where your Apex code needs to query setup information in order to execute business logic, even if that is not info you would normally disclose to the end user. I would suggest you create a helper class that you use for all these "setup queries". In the helper, query the tables directly, bypassing the access layer, but ensure the data you return doesn't represent sensitive information.
If the company is uncomfortable bypassing the access layer ever, create accompanying technical documentation that explains exactly how your code is still operating within their security requirements. Point to it from the comments of the helper file for future reference.
without sharing
permissions? – Renato Oliveira Apr 28 '19 at 15:08