If you take the (natural) JOIN of ANIMALS and PREFERRED_FOOD, then you get a table in which for each animal, its type and its preferred food are listed.
You want that combination to be "valid" for each individual animal where "valid" means "to appear in the enumeration of valid animal type/food type combinations that are listed in FOOD.
So you have a constraint that is somewhat similar to an FK, but this time the "foreign key" appears not in a base table, but in a join of two tables. For this type of constraint, the SQL language has CHECK constraints and ASSERTIONS.
The ASSERTION version is the simplest. It is a constraint like (I've been somewhat liberal with the attribute names in order to avoid mere attribute renames that obfuscate the point)
CREATE ASSERTION <name for your constraint here>
CHECK NOT EXISTS (SELECT ANIMAL_TYPE, FOOD_TYPE
FROM ANIMALS NATURAL JOIN PREF_FOOD
WHERE (ANIMAL_TYPE, FOOD_TYPE) NOT IN
SELECT ANIMAL_TYPE, FOOD_TYPE FROM FOOD_TYPE);
But your average SQL engine won't support ASSERTIONs. So you have to use CHECK constraints. For the PREF_FOOD table, for example, the CHECK constraint you need might look something like
CHECK EXISTS (SELECT 1
FROM FOOD NATURAL JOIN ANIMAL
WHERE ANIMAL_TYPE = <animal type of inserted row> AND
FOOD_TYPE = <food type of inserted row>);
In theory, this should suffice to enforce your constraint, but then again your average SQL engine will once again not support this kind of CHECK constraint, because of the references to tables other than the one the constraint is defined on.
So the options you have is to resort to rather complex (*) setups like catcall's, or enforcing the constraint using triggers (and you'll have to write quite a lot of them (three or six at least, haven't thought this through in detail), and your next best option is to enforce this in application code, and once again there will be three or six (more or less) distinct places where the same number of distinct checks need to be implemented.
In all of these three scenario's, you will preferably want to document the existence of the constraint, and what exactly it is about, in some other place. None of the three will make it very obvious to a third party reading this design what the heck this is all about.
(*) "complex" might not exactly be the right word, but note that such solutions rely on deliberate redundancy, thus deliberately going below 3NF with the design. And this means that your design is exposed to update anomalies, meaning that it will be harder for the user to update the database AND keep it consistent (precisely because of the deliberate redundancies).