diff --git a/dlls/winedos/int20.c b/dlls/winedos/int20.c
index 45fbea0431018dbd6fef7b2ce4a23d063777bb1a..a333b319a8c3c2664929dcc1f410f4fcebae5d0b 100644
--- a/dlls/winedos/int20.c
+++ b/dlls/winedos/int20.c
@@ -18,10 +18,10 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <stdlib.h>
-#include "winbase.h"
 #include "dosexe.h"
-#include "miscemu.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(int);
 
 /**********************************************************************
  *	    DOSVM_Int20Handler (WINEDOS16.132)
@@ -30,9 +30,10 @@
  */
 void WINAPI DOSVM_Int20Handler( CONTEXT86 *context )
 {
-    /* FIXME: Is this correct in DOS DPMI? */
-    if (ISV86(context))
+    if (DOSVM_IsWin16())
+        ExitThread( 0 );
+    else if(ISV86(context))
         MZ_Exit( context, TRUE, 0 );
     else
-        ExitThread(0);
+        ERR( "Called from DOS protected mode\n" );
 }
diff --git a/dlls/winedos/int21.c b/dlls/winedos/int21.c
index f050be04bf006e346722a18e8c85badc743a7018..e7806446ba46d7cb7456f5602ab4a227f9854623 100644
--- a/dlls/winedos/int21.c
+++ b/dlls/winedos/int21.c
@@ -38,6 +38,7 @@
 #include "winuser.h"
 #include "wine/unicode.h"
 #include "wine/debug.h"
+#include "wine/exception.h"
 
 /*
  * FIXME: Delete this reference when all int21 code has been moved to winedos.
@@ -2623,8 +2624,10 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context )
         TRACE("TERMINATE PROGRAM\n");
         if (DOSVM_IsWin16())
             ExitThread( 0 );
-        else
+        else if(ISV86(context))
             MZ_Exit( context, FALSE, 0 );
+        else
+            ERR( "Called from DOS protected mode\n" );
         break;
 
     case 0x01: /* READ CHARACTER FROM STANDARD INPUT, WITH ECHO */
@@ -3398,8 +3401,16 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context )
         TRACE( "EXIT with return code %d\n", AL_reg(context) );
         if (DOSVM_IsWin16())
             ExitThread( AL_reg(context) );
-        else
+        else if(ISV86(context))
             MZ_Exit( context, FALSE, AL_reg(context) );
+        else
+        {
+            /*
+             * Exit from DPMI.
+             */            
+            DWORD rv = AL_reg(context);
+            RaiseException( EXCEPTION_VM86_INTx, 0, 1, &rv );
+        }
         break;
 
     case 0x4d: /* GET RETURN CODE */
diff --git a/dlls/winedos/int31.c b/dlls/winedos/int31.c
index 2201db3fcb949f974134ca02213a0684510cdc70..91af7b6eda241ebd208be4dcaf559e42a2d1c1a0 100644
--- a/dlls/winedos/int31.c
+++ b/dlls/winedos/int31.c
@@ -69,6 +69,7 @@ typedef struct tagRMCB {
 static RMCB *FirstRMCB = NULL;
 static WORD dpmi_flag;
 static void* lastvalloced = NULL;
+static BYTE DPMI_retval;
 
 /**********************************************************************
  *          DOSVM_IsDos32
@@ -100,6 +101,14 @@ static WINE_EXCEPTION_FILTER(dpmi_exception_handler)
         DOSVM_SendQueuedEvents(context);
         return EXCEPTION_CONTINUE_EXECUTION;
     }
+    else if (rec->ExceptionCode == EXCEPTION_VM86_INTx)
+    {
+        if (ISV86(context))
+            ERR( "Real mode INTx caught by protected mode handler!\n" );
+        DPMI_retval = (BYTE)rec->ExceptionInformation[0];
+        return EXCEPTION_EXECUTE_HANDLER;
+    }
+
 #endif
     return EXCEPTION_CONTINUE_SEARCH;
 }
@@ -593,8 +602,14 @@ static void StartPM( CONTEXT86 *context )
     } 
     __ENDTRY
 
-    /* in the current state of affairs, we won't ever actually return here... */
-    /* we should have int21/ah=4c do it someday, though... */
+    TRACE( "Protected mode DOS program is terminating\n" );
+
+    /*
+     * FIXME: Instead of calling ExitThread, we should release all
+     *        allocated protected mode resources and call MZ_Exit
+     *        using real mode context. See DPMI specification.
+     */
+    ExitThread( DPMI_retval );
 
 #if 0
     FreeSelector16(psp->environment);
diff --git a/dlls/winedos/module.c b/dlls/winedos/module.c
index cce91a145d6533777dedd51d1e19d9889e0af974..f7dc102471af73f4b53ac2f66257419dcb98e697 100644
--- a/dlls/winedos/module.c
+++ b/dlls/winedos/module.c
@@ -623,7 +623,7 @@ static void MZ_Launch( LPCSTR cmdtail, int length )
   loop_thread = 0; loop_tid = 0;
 
   VGA_Clean();
-  ExitThread(rv);
+  ExitProcess(rv);
 }
 
 /***********************************************************************