You should be able to extend the standard dynamic programming problem with one constraint to handle two or more constraints.
As a refresher, the standard DP solution for the knapsack problem works by ordering the items in some order, then answering all questions of the following form:
What is the maximum value that can be produced using the first i items without exceeding weight w?
This turns into a 2D table, with one axis for how many items are being considered and another for the different possible weight values. To fill in the table, you fill in the 1D slice of entries where i = 0 by setting them to zero (you can’t get any value if you have no items), then filling in the 1D slice where i = 1 by considering whether to include or exclude the first item, the slice where i = 2 by considering whether to include or exclude the second item, etc. The runtime is then O(nW), where n is the number of items and W is the maximum allowable weight, since those are the dimensions of the table and you do O(1) work per entry.
If you now have two constraints (weight and volume), you can solve all problems of the following form:
What is the maximum value that can be produced using the first i items without exceeding weight w or volume v?
This turns into a 3D table, with one axis for how many items are being considered, another for the different possible weight values, and a third for the possible volume values. To fill in the table, you fill in the 2D slice of entries where i = 0 by setting them to zero (you can’t get any value if you have no items), then filling in the 2D slice where i = 1 by considering whether to include or exclude the first item, the slice where i = 2 by considering whether to include or exclude the second item, etc. The runtime is O(nWV), where n is the number of items, W is the maximum allowable weight, and V is the maximum allowable volume(instead of value), since that’s the number of table entries and it takes O(1) work to fill each in.
Do you see how to adapt this for larger numbers of constraints?