Goals from Henrikh Mkhitaryan, Marco Reus and Jonas Hofmann condemned ten-man Bayern to their first Bundesliga loss in Munich since October 2012.
The reigning European champions have failed to win any of the three league matches they have played since wrapping up the German title last month.
“We never made the made right decisions, we didn’t concentrate enough and we had problems with our rhythm and build-up play,” said Bayern’s director of sport Matthias Sammer.
“We’re German champions, but we have to be careful and get back to playing well.”
The win means second-placed Dortmund move three points clear of rivals Schalke 04, who are third, and means they are now all but certain of returning to the Champions League next season.
Both Bayern and Dortmund have German Cup semi-finals to look forward to in midweek but Bayern coach Pep Guardiola and his opposite number Jurgen Klopp named strong line-ups.
The visitors, however, left star striker Robert Lewandowski on the bench. The Polish international, who is set to join Bayern next season, was replaced by Pierre-Emerick Aubameyang.
The first half was short on chances but Dortmund hit the front after 20 minutes.
Aubamayeng flicked Hofmann’s throw-in on to Reus inside the box and the German international then found Mkhitaryan.
The Armenian midfielder took a touch before calmly slotting his seventh goal of the season beyond Bayern goalkeeper Manuel Neuer.
It was the fifth game in a row in which Bayern had fallen behind and the closest they came to equalising was when Mario Mandzukic volleyed straight at Roman Weidenfeller shortly before the interval.
Neuer was forced off with a calf problem at the break, with Lukas Raeder coming in for the German number one.
The 20-year-old substitute conceded just four minutes later as Mkhitaryan broke swiftly from his own half and then threaded a perfect pass through to Aubameyang.
The Gabonese striker unselfishly left Reus with a simple finish for his 14th goal of the campaign.
Seven minutes later Dortmund made the points safe. Bayern defender Javi Martinez slipped when chasing a long ball over the top, leaving Hofmann with plenty of time to pick his spot.
Mandzukic had a goal chalked off for offside before Rafinha was sent off for hitting out at Mkhitaryan in injury time as Dortmund gained revenge for a 3-0 defeat in November’s reverse fixture.
– Wolves move up to fourth –
Earlier VfL Wolfsburg continued their push for a place in next season’s Champions League after a thumping 4-1 win over Nuremburg saw them go fourth.
The second-from-bottom visitors took the lead through Markus Feulner but Wolfsburg hit back with two goals in four minutes.
First Ivica Olic slid home his 12th goal of the season from a Kevin de Bruyne cross, then the Belgian midfielder teed up another Croatian, Ivan Perisic, after 22 minutes.
Junior Malanda drilled home midway through the second half before Olic set up Perisic as Nuremberg lost for the seventh time in eight matches.
The win saw Wolfsburg leapfrog Bayer Leverkusen, who play on Sunday, and Borussia Moenchengladbach, who were held to a 1-1 draw at home to VfB Stuttgart.
Daniel Didavi slammed home early on for Stuttgart but Juan Arango’s header with a minute remaining salvaged a point for Moenchengladbach.
Stuttgart are now one point clear of third-from-bottom Hamburg, who lost 2-1 at Hanover 96.
Hamburg coach Mirko Slomka returned to Hanover for the first time since his sacking in December but his new team fell behind when Lars Stindl headed home on nine minutes.
Hamburg levelled through a Hakan Calanoglou free-kick but Didier Ya Konan scrambled home with four minutes left to help Hanover pull five points clear of the relegation zone.
In the other meeting of two relegation candidates, Freiburg defeated bottom club Eintracht Braunschweig 2-0, while Europa League hopefuls Mainz swept aside mid-table Werder Bremen 3-0.