diff --git a/extension-dev.code-workspace b/extension-dev.code-workspace
index 73b8f8e4c6..795c63133c 100644
--- a/extension-dev.code-workspace
+++ b/extension-dev.code-workspace
@@ -212,6 +212,20 @@
         "type": "coreclr",
         "request": "attach",
         "processId": "${command:pickProcess}",
+        "justMyCode": true,
+        "suppressJITOptimizations": true,
+        "symbolOptions": {
+          "searchPaths": [],
+          "searchMicrosoftSymbolServer": true,
+          "searchNuGetOrgSymbolServer": true
+        }
+      },
+      {
+        // https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
+        "name": "Attach to Editor Services (!jmc)",
+        "type": "coreclr",
+        "request": "attach",
+        "processId": "${command:pickProcess}",
         "justMyCode": false,
         "suppressJITOptimizations": true,
         "symbolOptions": {
diff --git a/src/features/BreakpointManager.ts b/src/features/BreakpointManager.ts
new file mode 100644
index 0000000000..a1a3e395e4
--- /dev/null
+++ b/src/features/BreakpointManager.ts
@@ -0,0 +1,193 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+import vscode = require("vscode");
+import { LanguageClient } from "vscode-languageclient/node";
+import { Range, NotificationType, RequestType } from "vscode-languageserver-protocol";
+import { LanguageClientConsumer } from "../languageClientConsumer";
+import { Logger } from "../logging";
+
+export const BreakpointChangedNotificationType = new NotificationType<IPsesBreakpointChangedEventArgs>("powerShell/breakpointsChanged");
+export const SetBreakpointRequestType = new RequestType<IPsesBreakpoint, string, void>("powerShell/setBreakpoint");
+export const BreakpointRemovedNotificationType = new NotificationType<IPsesBreakpoint>("powerShell/breakpointRemoved");
+export const BreakpointEnabledChanged = new NotificationType<IPsesBreakpoint>("powerShell/breakpointEnabledChanged");
+
+interface IPsesBreakpoint {
+    id: string,
+    enabled: boolean,
+    condition?: string,
+    hitCondition?: string,
+    logMessage?: string,
+    location?: IPsesLocation,
+    functionName?: string,
+}
+
+interface IPsesLocation {
+    uri: string,
+    range: Range,
+}
+
+interface IPsesBreakpointChangedEventArgs {
+    added: IPsesBreakpoint[],
+    removed: IPsesBreakpoint[],
+    changed: IPsesBreakpoint[],
+}
+
+export class BreakpointManager extends LanguageClientConsumer{
+    private eventRegistration: vscode.Disposable | undefined;
+
+    private notificationRegistration: vscode.Disposable | undefined;
+
+    private requestRegistration: vscode.Disposable | undefined;
+
+    private logger: Logger;
+
+    constructor(logger: Logger) {
+        super();
+
+        this.logger = logger;
+    }
+
+    public override setLanguageClient(languageClient: LanguageClient): void {
+        this.languageClient = languageClient;
+
+        this.requestRegistration = this.languageClient.onRequest(
+            SetBreakpointRequestType,
+            bp => {
+                const clientBp: vscode.Breakpoint | undefined = this.toVSCodeBreakpoint(bp);
+                if (clientBp === undefined) {
+                    return -1;
+                }
+
+                vscode.debug.addBreakpoints([clientBp]);
+                return clientBp.id;
+            });
+
+        this.notificationRegistration = this.languageClient.onNotification(
+            BreakpointChangedNotificationType.method,
+            (eventArgs) => {
+                this.handleServerBreakpointChanged(this.toVSCodeBreakpointsChanged(eventArgs));
+            });
+
+        this.eventRegistration = vscode.debug.onDidChangeBreakpoints(
+            (eventArgs) => {
+                this.handleClientBreakpointChanged(eventArgs)
+                    .catch((reason) => {
+                        this.logger.writeError(`Error occurred while handling client breakpoint changed: ${reason}`);
+                    });
+            },
+            this);
+    }
+
+    private handleServerBreakpointChanged(eventArgs: vscode.BreakpointsChangeEvent): void {
+        vscode.debug.removeBreakpoints(eventArgs.removed);
+    }
+
+    private async handleClientBreakpointChanged(eventArgs: vscode.BreakpointsChangeEvent): Promise<void> {
+        if (this.languageClient === undefined) {
+            return;
+        }
+
+        await this.languageClient.sendNotification(
+            BreakpointChangedNotificationType,
+            this.toPsesBreakpointsChanged(eventArgs));
+    }
+
+    private toVSCodeBreakpointsChanged(eventArgs: IPsesBreakpointChangedEventArgs): vscode.BreakpointsChangeEvent {
+        const map: Map<string, vscode.Breakpoint> = new Map<string, vscode.Breakpoint>(
+            vscode.debug.breakpoints.map(bp => [bp.id, bp]));
+
+        const isBreakpoint = (bp: vscode.Breakpoint | undefined): bp is vscode.Breakpoint => bp !== undefined;
+        return {
+            added: eventArgs.added.map((bp) => this.toVSCodeBreakpoint(bp, map)).filter(isBreakpoint),
+            removed: eventArgs.removed.map((bp) => this.toVSCodeBreakpoint(bp, map)).filter(isBreakpoint),
+            changed: eventArgs.changed.map((bp) => this.toVSCodeBreakpoint(bp, map)).filter(isBreakpoint),
+        };
+    }
+
+    private toPsesBreakpointsChanged(eventArgs: vscode.BreakpointsChangeEvent): IPsesBreakpointChangedEventArgs {
+        return {
+            added: eventArgs.added.map((bp) => this.toPsesBreakpoint(bp)),
+            removed: eventArgs.removed.map((bp) => this.toPsesBreakpoint(bp)),
+            changed: eventArgs.changed.map((bp) => this.toPsesBreakpoint(bp)),
+        };
+    }
+
+    private toVSCodeBreakpoint(breakpoint: IPsesBreakpoint, map?: Map<string, vscode.Breakpoint>): vscode.Breakpoint | undefined {
+        const existing: vscode.Breakpoint | undefined = map?.get(breakpoint.id);
+        if (existing !== undefined) {
+            return existing;
+        }
+
+        if (breakpoint.location !== undefined) {
+            const bp = new vscode.SourceBreakpoint(
+                new vscode.Location(
+                    vscode.Uri.parse(breakpoint.location.uri),
+                    new vscode.Range(
+                        breakpoint.location.range.start.line,
+                        breakpoint.location.range.start.character,
+                        breakpoint.location.range.end.line,
+                        breakpoint.location.range.end.character)),
+                breakpoint.enabled,
+                breakpoint.condition,
+                breakpoint.hitCondition,
+                breakpoint.logMessage);
+
+            return bp;
+        }
+
+        if (breakpoint.functionName !== undefined) {
+            const fbp = new vscode.FunctionBreakpoint(
+                breakpoint.functionName,
+                breakpoint.enabled,
+                breakpoint.condition,
+                breakpoint.hitCondition,
+                breakpoint.logMessage);
+
+            return fbp;
+        }
+
+        this.logger.writeError(`Unable to translate PSES breakpoint: ${JSON.stringify(breakpoint)}`);
+        return undefined;
+    }
+
+    private toPsesBreakpoint(breakpoint: vscode.Breakpoint): IPsesBreakpoint {
+        let psesLocation: IPsesLocation | undefined = undefined;
+        if (breakpoint instanceof vscode.SourceBreakpoint) {
+            psesLocation = {
+                uri: breakpoint.location.uri.toString(),
+                range: {
+                    start: {
+                        character: breakpoint.location.range.start.character,
+                        line: breakpoint.location.range.start.line,
+                    },
+                    end: {
+                        character: breakpoint.location.range.end.character,
+                        line: breakpoint.location.range.end.line,
+                    },
+                },
+            };
+        }
+
+        let functionName: string | undefined = undefined;
+        if (breakpoint instanceof vscode.FunctionBreakpoint) {
+            functionName = breakpoint.functionName;
+        }
+
+        return {
+            id: breakpoint.id,
+            enabled: breakpoint.enabled,
+            condition: breakpoint.condition,
+            hitCondition: breakpoint.hitCondition,
+            logMessage: breakpoint.logMessage,
+            location: psesLocation,
+            functionName,
+        };
+    }
+
+    dispose(): void {
+        this.eventRegistration?.dispose();
+        this.notificationRegistration?.dispose();
+        this.requestRegistration?.dispose();
+    }
+}
diff --git a/src/main.ts b/src/main.ts
index 5b0fee117e..a9a16e6e9e 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -29,6 +29,7 @@ import { SessionManager } from "./session";
 import { LogLevel, getSettings } from "./settings";
 import { PowerShellLanguageId } from "./utils";
 import { LanguageClientConsumer } from "./languageClientConsumer";
+import { BreakpointManager } from "./features/BreakpointManager";
 
 // The most reliable way to get the name and version of the current extension.
 // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-var-requires
@@ -159,6 +160,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<IPower
         new PickPSHostProcessFeature(logger),
         new HelpCompletionFeature(),
         new CustomViewsFeature(),
+        new BreakpointManager(logger),
         new PickRunspaceFeature(logger),
         externalApi
     ];
diff --git a/src/session.ts b/src/session.ts
index d448de4c8b..aacf970c26 100644
--- a/src/session.ts
+++ b/src/session.ts
@@ -618,6 +618,7 @@ export class SessionManager implements Middleware {
                 enableProfileLoading: this.sessionSettings.enableProfileLoading,
                 initialWorkingDirectory: await validateCwdSetting(this.logger),
                 shellIntegrationEnabled: vscode.workspace.getConfiguration("terminal.integrated.shellIntegration").get<boolean>("enabled"),
+                supportsBreakpointSync: true,
             },
             errorHandler: {
                 // Override the default error handler to prevent it from