As a general rule when you access a code segment directly you can only do that for segments with the same privilege.
This is what the Non Conforming Code Segments (NCCS) are used for.
Intel made has the favor of introducing also Conforming Code Segment (CCS) that can be accessed by less privileged applications (in case the kernel need to share some code without elevating the privilege of the caller).
Accessing a code segment directly never change the current privilege, the CPL of the target code is the CPL of the caller.
The RPL also takes no role. It is ignored for CCS and must be less or equal to the caller CPL for NCCS (this is likely a side effect).
The rules are:
NCCS
1. Caller CPL must be equal to descriptor DPL (Same privilege)
2. The target code will be run with CPL equal to the caller CPL regardless of the RPL used in the selector.
3. The selector RPL must be less or equal to the caller CPL.
CCS
1. Caller CPL must be greater or equal to descriptor DPL (less privileged)
2. The target code will be run with CPL equal to the caller CPL regardless of the RPL used in the selector.
As you can see accessing directly the code segment doesn't change the CPL (and there is no stack change).
To change privilege (CPL) Intel introduced Call Gates. With CG, as with Data Segments, the RPL let you impersonate a less privileged program.
If a CG as DPL=2 (and the target selector also have DPL>=2) and your code has CPL=0, you can choose to perform the call as a user mode application with CPL=3 (thereby not gaining the access) or as a kernel component with CPL=2 (gaining the access but without the possibility to call other more privileged code segments).