I think your issue is a modeling one, as you skipped a few relations along the way. You can enforce your data consistency exclusively with the schema, no need for code enforcement with triggers or otherwise.
Also, why use surrogate keys for such a model? Try using the natural keys which in your case are short, stable, and familiar, and see hot it simplifies your queries.
Here is my take:
Courses:
Course PK <-- This is the name of the course, the one you use in the 'real world'
Semesters:
Semester PK <-- Summer, Spring, Winter, Fall or whatever you use to distinguish them
Course_Schedules:
Course REF Courses,
Semester REF Semesters,
Year ( in case not all courses are offered in the same semesters every year),
PK (Course, Semester, Year)
Students:
Student PK <-- Whatever you use to distinguish students in the real world
Course_Registrations:
Course,
Semester,
Year,
Student,
FK (Course, Semester, Year) REF Course_Schedules <-- Only 'real' scheduled courses,
PK (Course, Semester, Year, Student) <-- Student may repeat the course in different years
Course_Evaluations:
I think you are missing part of the key here, in the model you showed every course can have only one evaluation...
Who evaluates it? add to PK as needed
Course,
Semester,
Year,
-- other properties --
PK (Course, Semester, Year, {missing attribute?}),
FK (Course, Semester, Year) REF Course Schedules
Course_Student_Evaluation:
Course,
Semester,
Year,
Student,
PK (Course, Semester, Year, Student),
FK (Course, Semester, Year) REF Course_Schedules
Now you can see that since both Course_Evaluations and Course_Student_Evaluations have DRI to Course_Schedules, it enforces everything you asked for, and more..
HTH