Karim Benzema opened the scoring in the 12th minute by converting a rebound after Marc-Andre Ter Stegen saved from Vinicius Junior, with Fede Valverde drilling home the second from the edge of the box before the break.
Ferran Torres pulled one back for Barcelona in the final stages after good work by Ansu Fati, but Rodrygo won and converted a late penalty to ensure Carlo Ancelotti's side inflicted Barcelona's first domestic defeat of the season.
Madrid ended the Catalans' seven-game winning streak in the league and added to the still-raw pain of their struggles in Europe, where they are on the verge of Champions League elimination.
Barcelona, who spent heavily in the summer to try and catch up with their rivals, now trail them by three points. The Catalans had conceded just one league goal in eight games before the Clasico but shipped double that tally in the first half, leaving Madrid as the division's only unbeaten side.
After a damaging draw with Inter Milan midweek that left Barcelona's European hopes hanging by a thread, Xavi made changes.
Jules Kounde returned after injury to strengthen the defence, with veteran defender Gerard Pique, who made a costly error against the Italians, dropping out. Frenkie de Jong and Alejandro Balde also came into the side.
Xavi's counterpart Ancelotti had fewer decisions to make, with Valverde getting the nod over Rodrygo on the right of the attack, while Andriy Lunin started in goal with Thibaut Courtois not ready to return after suffering sciatica.
Last season Barcelona's best moment came at the Bernabeu, as Xavi's side earned a surprising 4-0 win, but this visit found them at their lowest ebb since the Spanish World Cup winner took charge.